D:\a\tools.proto\tools.proto\dynamic\src\buffer\bytes.rs
Line | Count | Source |
1 | | // Copyright (c) 2025, BlockProject 3D |
2 | | // |
3 | | // All rights reserved. |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without modification, |
6 | | // are permitted provided that the following conditions are met: |
7 | | // |
8 | | // * Redistributions of source code must retain the above copyright notice, |
9 | | // this list of conditions and the following disclaimer. |
10 | | // * Redistributions in binary form must reproduce the above copyright notice, |
11 | | // this list of conditions and the following disclaimer in the documentation |
12 | | // and/or other materials provided with the distribution. |
13 | | // * Neither the name of BlockProject 3D nor the names of its contributors |
14 | | // may be used to endorse or promote products derived from this software |
15 | | // without specific prior written permission. |
16 | | // |
17 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
18 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
19 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
20 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
21 | | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
22 | | // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
23 | | // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
24 | | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
25 | | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
26 | | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
27 | | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | |
29 | | use std::alloc::{alloc, dealloc, realloc, Layout}; |
30 | | use std::cell::Cell; |
31 | | use std::ptr::copy_nonoverlapping; |
32 | | use std::ops::{Range, RangeFrom, RangeTo}; |
33 | | use std::ptr::NonNull; |
34 | | use std::slice; |
35 | | |
36 | | pub trait Index { |
37 | | type Output; |
38 | | fn index(&self, bytes: &Bytes) -> Self::Output; |
39 | | } |
40 | | |
41 | | impl Index for usize { |
42 | | type Output = u8; |
43 | | |
44 | 0 | fn index(&self, bytes: &Bytes) -> Self::Output { |
45 | 0 | let ptr = bytes.bytes.get(); |
46 | 0 | let len = bytes.len.get(); |
47 | 0 | if *self > len { Branch (47:12): [Folded - Ignored]
Branch (47:12): [True: 0, False: 0]
|
48 | 0 | panic!("Cannot index, index out of bounds: {} > {}", *self, len); |
49 | 0 | } |
50 | 0 | unsafe { *ptr.add(*self).as_ptr() } |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl Index for Range<usize> { |
55 | | type Output = Bytes; |
56 | | |
57 | 86 | fn index(&self, bytes: &Bytes) -> Self::Output { |
58 | 86 | let required_len = self.len(); |
59 | 86 | let len = bytes.len.get(); |
60 | 86 | if required_len > len { Branch (60:12): [True: 0, False: 8]
Branch (60:12): [True: 0, False: 78]
|
61 | 0 | panic!("Cannot slice, range out of bounds: {} > {} ({}..{})", required_len, len, self.start, self.end); |
62 | 86 | } |
63 | 86 | let bytes = unsafe { bytes.bytes.get().add(self.start) }; |
64 | 86 | Bytes { |
65 | 86 | bytes: Cell::new(bytes), |
66 | 86 | len: Cell::new(self.len()), |
67 | 86 | owned: false, |
68 | 86 | } |
69 | 86 | } |
70 | | } |
71 | | |
72 | | impl Index for RangeFrom<usize> { |
73 | | type Output = Bytes; |
74 | | |
75 | 21 | fn index(&self, bytes: &Bytes) -> Self::Output { |
76 | 21 | (self.start..bytes.len.get()).index(bytes) |
77 | 21 | } |
78 | | } |
79 | | |
80 | | impl Index for RangeTo<usize> { |
81 | | type Output = Bytes; |
82 | | |
83 | 36 | fn index(&self, bytes: &Bytes) -> Self::Output { |
84 | 36 | (0..self.end).index(bytes) |
85 | 36 | } |
86 | | } |
87 | | |
88 | | #[derive(Debug)] |
89 | | pub struct Bytes { |
90 | | bytes: Cell<NonNull<u8>>, |
91 | | len: Cell<usize>, |
92 | | owned: bool, |
93 | | } |
94 | | |
95 | | impl Bytes { |
96 | 13 | pub fn from_slice(slice: &[u8]) -> Bytes { |
97 | 13 | let ptr = unsafe { alloc(Layout::array::<u8>(slice.len()).unwrap()) }; |
98 | 13 | unsafe { copy_nonoverlapping(slice.as_ptr(), ptr, slice.len()) }; |
99 | 13 | Bytes { |
100 | 13 | bytes: unsafe { Cell::new(NonNull::new_unchecked(ptr)) }, |
101 | 13 | len: Cell::new(slice.len()), |
102 | 13 | owned: true, |
103 | 13 | } |
104 | 13 | } |
105 | | |
106 | 4 | pub fn with_capacity(capacity: usize) -> Bytes { |
107 | 4 | let ptr = unsafe { alloc(Layout::array::<u8>(capacity).unwrap()) }; |
108 | 4 | unsafe { ptr.write_bytes(0, capacity); } |
109 | 4 | Bytes { |
110 | 4 | bytes: unsafe { Cell::new(NonNull::new_unchecked(ptr)) }, |
111 | 4 | len: Cell::new(capacity), |
112 | 4 | owned: true, |
113 | 4 | } |
114 | 4 | } |
115 | | |
116 | 11 | pub unsafe fn copy(&mut self, slice: &[u8]) -> bool { |
117 | 11 | let added_bytes6 = match self.resize(slice.len()) { |
118 | 6 | Some(v) => v, |
119 | | None => { |
120 | 5 | *self = Bytes::from_slice(slice); |
121 | 5 | return true; |
122 | | } |
123 | | }; |
124 | 6 | copy_nonoverlapping(slice.as_ptr(), self.bytes.get().as_ptr(), slice.len()); |
125 | 6 | added_bytes == 0 |
126 | 11 | } |
127 | | |
128 | 11 | unsafe fn resize(&mut self, new_len: usize) -> Option<usize> { |
129 | 11 | let mut ptr = self.bytes.get(); |
130 | 11 | let len = self.len.get(); |
131 | 11 | if new_len == len { Branch (131:12): [True: 3, False: 0]
Branch (131:12): [True: 2, False: 6]
|
132 | 5 | return Some(0); |
133 | 6 | } |
134 | 6 | if new_len < len { Branch (134:12): [True: 0, False: 0]
Branch (134:12): [True: 1, False: 5]
|
135 | | //FIXME: we need capacity support |
136 | 1 | return Some(0); |
137 | 5 | } |
138 | 5 | if !self.owned { Branch (138:12): [True: 0, False: 0]
Branch (138:12): [True: 5, False: 0]
|
139 | 5 | return None; |
140 | 0 | } |
141 | 0 | ptr = unsafe { NonNull::new_unchecked(realloc(ptr.as_ptr(), Layout::array::<u8>(len).unwrap(), new_len)) }; |
142 | | // The number of bytes which were added in the realloc. |
143 | 0 | let ending = new_len - len; |
144 | | //unsafe { write_bytes(ptr.add(len).as_ptr(), 0, ending) } |
145 | 0 | self.bytes.set(ptr); |
146 | 0 | self.len.set(new_len); |
147 | 0 | Some(ending) |
148 | 11 | } |
149 | | |
150 | 201 | pub fn as_bytes(&self) -> &[u8] { |
151 | 201 | let ptr = self.bytes.get(); |
152 | 201 | let len = self.len.get(); |
153 | 201 | unsafe { slice::from_raw_parts(ptr.as_ptr(), len) } |
154 | 201 | } |
155 | | |
156 | 19 | pub fn as_bytes_mut(&mut self) -> &mut [u8] { |
157 | 19 | let ptr = self.bytes.get(); |
158 | 19 | let len = self.len.get(); |
159 | 19 | unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), len) } |
160 | 19 | } |
161 | | |
162 | 86 | pub fn index<I: Index>(&self, index: I) -> I::Output { |
163 | 86 | index.index(self) |
164 | 86 | } |
165 | | |
166 | 144 | pub fn len(&self) -> usize { |
167 | 144 | self.len.get() |
168 | 144 | } |
169 | | |
170 | 40 | pub unsafe fn delete(&mut self) { |
171 | 40 | if self.owned { Branch (171:12): [True: 1, False: 4]
Branch (171:12): [True: 9, False: 26]
|
172 | 10 | unsafe { dealloc(self.bytes.get().as_ptr(), Layout::array::<u8>(self.len.get()).unwrap()) } |
173 | 30 | } |
174 | 40 | } |
175 | | } |